import logging
import sys
from pathlib import Path
from nicegui import ui, app
import pandas as pd
from typing import List, Dict
import time
import threading
import os
import json
import openpyxl

from utils.common.context_utils import check_license

# 初始数据 - 根据图片中的单位设置
initial_data: List[Dict] = [
    {'unit': '箱火一营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
    {'unit': '箱火二营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
    {'unit': '远火一营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
    {'unit': '远火二营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
    {'unit': '车载一营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
    {'unit': '车载二营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
    {'unit': '目标保障营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
    {'unit': '作战支援营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
    {'unit': '勤务保障营', 'gold': 0, 'silver': 0, 'bronze': 0, 'total': 0},
]


# 数据持久化函数
def load_data():
    """从文件加载保存的数据"""
    data_file = Path('competition_data.json')
    if data_file.exists():
        try:
            with open(data_file, 'r', encoding='utf-8') as f:
                saved_data = json.load(f)
                # 检查是否包含标题
                if isinstance(saved_data, dict) and 'data' in saved_data:
                    return saved_data
                # 旧格式数据转换为新格式
                return {
                    'title': '昆仑杯比武竞赛排行榜',
                    'data': saved_data
                }
        except Exception as e:
            print(f"加载数据失败: {e}")
            return {
                'title': '昆仑杯比武竞赛排行榜',
                'data': initial_data.copy()
            }
    return {
        'title': '昆仑杯比武竞赛排行榜',
        'data': initial_data.copy()
    }


def save_data(data):
    """保存数据到文件"""
    try:
        with open('competition_data.json', 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    except Exception as e:
        print(f"保存数据失败: {e}")


# 共享状态管理
class CompetitionState:
    def __init__(self):
        self.saved_data = load_data()  # 从文件加载数据
        self.data = self.saved_data['data']
        self.title = self.saved_data.get('title', '昆仑杯比武竞赛排行榜')
        self.update_callbacks = []
        self.title_update_callbacks = []
        self.auto_refresh_thread = None
        self.running = True

    def update_score(self, unit, medal_type, value):
        value_int = int(value) if value != '' else 0

        for item in self.data:
            if item['unit'] == unit:
                item[medal_type] = value_int
                # 自动计算总分
                item['total'] = item['gold'] * 3 + item['silver'] * 2 + item['bronze'] * 1
                break

        # 保存更新后的数据
        self.save_state()
        self.notify_update()

    def update_title(self, new_title):
        self.title = new_title
        # 保存更新后的数据
        self.save_state()
        self.notify_title_update()

    def save_state(self):
        """保存当前状态到文件"""
        save_data({
            'title': self.title,
            'data': self.data
        })

    def notify_update(self):
        for callback in self.update_callbacks:
            callback()

    def notify_title_update(self):
        for callback in self.title_update_callbacks:
            callback(self.title)

    def register_callback(self, callback):
        self.update_callbacks.append(callback)

    def register_title_callback(self, callback):
        self.title_update_callbacks.append(callback)

    def start_auto_refresh(self):
        """启动自动刷新线程"""
        if self.auto_refresh_thread and self.auto_refresh_thread.is_alive():
            return

        self.running = True
        self.auto_refresh_thread = threading.Thread(target=self.auto_refresh_loop, daemon=True)
        self.auto_refresh_thread.start()

    def auto_refresh_loop(self):
        """自动刷新循环"""
        while self.running:
            time.sleep(10)  # 每10秒刷新一次
            self.notify_update()

    def stop_auto_refresh(self):
        """停止自动刷新"""
        self.running = False


comp_state = CompetitionState()

def setup_logging(default_path="logging-config.json", default_level=logging.INFO, env_key="LOG_CFG"):
    path = default_path
    value = os.getenv(env_key, None)
    if value:
        path = value
    if os.path.exists(path):
        with open(path, "r") as f:
            config = json.load(f)
            logging.config.dictConfig(config)
    else:
        logging.basicConfig(level=default_level)

# 大屏展示界面 - 红色和金黄色主题
def create_display_screen():
    def update_display():
        nonlocal table

        # 排序逻辑：总分 > 金牌 > 银牌 > 铜牌
        df = pd.DataFrame(comp_state.data)
        df = df.sort_values(
            by=['total', 'gold', 'silver', 'bronze'],
            ascending=[False, False, False, False]
        ).reset_index(drop=True)

        # 计算排名（考虑并列情况）
        display_data = []
        prev_total = None
        prev_rank = 0
        skip_count = 0

        for i, row in df.iterrows():
            current_total = (row['total'], row['gold'], row['silver'], row['bronze'])

            if current_total == prev_total:
                # 并列情况
                rank = prev_rank
                skip_count += 1
            else:
                # 新排名
                rank = i + 1 - skip_count
                prev_rank = rank
                prev_total = current_total

            display_data.append({
                'rank': rank,
                'unit': row['unit'],
                'gold': row['gold'],
                'silver': row['silver'],
                'bronze': row['bronze'],
                'total': row['total']
            })

        table.options['rowData'] = display_data
        table.update()

    # 大屏样式设置 - 红色和金黄色主题
    ui.add_head_html('''
        <style>
            .fullscreen {
                position: fixed;
                top: 0;
                left: 0;
                width: 100vw;
                height: 100vh;
                background: linear-gradient(135deg, #8b0000, #b22222), linear-gradient(to right, transparent calc(100% - 4px), #ffd700 4px); background-clip: padding-box, border-box;
                color: #ffd700;
                overflow: hidden;
                padding: 20px;
                box-sizing: border-box;
                font-family: 'Microsoft YaHei', sans-serif;
            }
            .title-bar {
                background: rgba(139, 0, 0, 0.7);
                border-radius: 10px;
                padding: 15px 30px;
                margin-bottom: 25px;
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
                border: 2px solid #ffd700;
                display: flex;
                align-items: center;
                justify-content: space-between;
                width: 100%;
            }
            .rank-table {
                background: rgba(178, 34, 34, 0.5);
                border-radius: 15px;
                padding: 0;
                box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
                backdrop-filter: blur(5px);
                border: 2px solid #ffd700;
                box-sizing: border-box;
                height: 100%;
            }
            .header-row {
                font-weight: bold;
                font-size: 1.8rem;
                border-bottom: 2px solid #ffd700;
                margin-bottom: 15px;
                text-align: center;
            }
            .highlight-row {
                background: linear-gradient(90deg, rgba(255,215,0,0.3), rgba(255,215,0,0.1));
                border-radius: 8px;
                border: 1px solid #ffd700;
            }
            .medal-icon {
                font-size: 1.8rem;
                vertical-align: middle;
                margin: 0 5px;
            }
            .logo-container {
                display: flex;
                align-items: center;
                margin-right: 20px;
            }
            .logo {
                max-height: 100px;
                max-width: 100px;
                border-radius: 10px;
                padding: 5px;
            }
            .title-container {
                flex-grow: 1;
                display: flex;
                justify-content: center;
                align-items: center;
            }
            .title-text {
                text-align: center;
                font-family: '华文行楷', serif;
            }
            html, body {
                margin: 0;
                padding: 0;
                height: 100%;
            }
            .time-display {
                background: rgba(0, 0, 0, 0.3);
                padding: 5px 15px;
                border-radius: 20px;
                border: 1px solid #ffd700;
            }
            .box-sizing-border-box {
                box-sizing: border-box !important;
            }
            /* 确保单元格内容垂直居中 */
            .rank-table .ag-body-viewport {
                height: 100% !important;
            }
            .rank-table .ag-row {
                height: 75px !important;
            }

            /* 隐藏表头 */
            /* 恢复表头显示 */
            .ag-root .ag-header .ag-header-row .ag-header-cell {
                background: linear-gradient(135deg, #8b0000, #b22222), linear-gradient(to right, transparent calc(100% - 4px), #ffd700 4px);
                background-clip: padding-box, border-box;
                color: #ffd700;
                font-weight: bold;
                font-size: 2rem;
                text-align: center;
                padding: 0 10px;
                line-height: 75px;
                box-sizing: border-box;
            }
            
            .ag-header-cell:last-child {
                border-right: 3px solid #ffd700 !important;
            }
            .ag-header, .ag-header-container, .ag-header-viewport {
                overflow: visible !important;
            }
            .ag-header, .ag-header-container {
                overflow: visible !important;
            }
            .ag-header-cell-text {
                text-align: center;
                width: 100%;
                white-space: nowrap;
            }
            .ag-root .ag-header-container .ag-header .ag-header-row .ag-header-cell.custom-header-border {
                background: linear-gradient(135deg, #8b0000, #b22222) !important;
                position: relative !important;
                overflow: visible !important;
            }
            .ag-root .ag-header-container .ag-header .ag-header-row .ag-header-cell.custom-header-border::after {
                content: '';
                position: absolute;
                right: 0;
                top: 0;
                height: 100%;
                width: 3px;
                background-color: #ffd700 !important;
                z-index: 999;
            }
            .ag-header-viewport {
                overflow: visible !important;
            }
            .ag-header-group-cell-label {
                justify-content: center !important;
            }
            /* 单位列使用华文行楷字体 */
            .unit-cell {
                font-family: 'Microsoft YaHei', serif !important;
            }
            /* 排名列特殊样式 */
            .rank-cell {
                font-weight: bold;
                font-size: 32px !important;
            }
            .gold-rank {
                background-color: gold;
                color: white;
                font-weight: bold;
                border-radius: 0 45% 45% 0;
                padding-top: 5px;
                padding-bottom: 5px;
                background-clip: content-box;
                height: 65px;
            }
            .silver-rank {
                background-color: #627e8e;
                color: white;
                font-weight: bold;
                border-radius: 0 45% 45% 0;
                padding-top: 5px;
                padding-bottom: 5px;
                background-clip: content-box;
                height: 65px;
            }
            .bronze-rank {
                background-color: #cd7f32;
                color: white;
                font-weight: bold;
                border-radius: 0 45% 45% 0;
                padding-top: 5px;
                padding-bottom: 5px;
                background-clip: content-box;
                height: 65px;
            }
        </style>
    ''')

    with ui.column().classes('fullscreen flex flex-col items-center box-sizing-border-box h-screen w-screen'):
        # 标题栏
        with ui.row().classes('title-bar h-[150px] w-full'):
            # 左侧LOGO - 使用指定的路径
            with ui.column().classes('logo-container'):
                ui.image('/images/logo.png').classes('logo w-[100px] h-[100px]')

            # 中间标题 - 水平居中
            with ui.column().classes('title-container'):
                title_label = ui.label(comp_state.title).classes('title-text text-8xl font-bold')

            # 右侧时间
            with ui.column().classes('time-display'):
                time_label = ui.label().classes('text-2xl font-bold')

        # 排行榜表格
        with ui.column().classes('rank-table w-full flex-1 overflow-y-scroll p-0 m-0 h-full'):            # 表头（我们手动创建的表头）
            # 数据表格 - 隐藏AG Grid自带的表头，确保内容垂直居中
            columns = [
                {
                    'headerName': "排名",
                    'field': "rank",
                    'flex': 5,
                    'cellClass': 'rank-cell box-sizing-border-box',  # 应用排名样式
                    'cellStyle': {
                          'fontSize': '30px',
                          'textAlign': 'center',
                          'height': '75px',
                          'display': 'flex',
                          'alignItems': 'center',
                          'justifyContent': 'center'
                    },  # 垂直居中
                    'cellClassRules': {
                        'gold-rank': 'data.rank === 1',
                        'silver-rank': 'data.rank === 2',
                        'bronze-rank': 'data.rank === 3'
                    }
                },
                {
                    'headerName': "单位",
                    'field': "unit",
                    'flex': 35,
                    'cellStyle': {
                        'fontSize': '30px',
                        'textAlign': 'center',
                        'height': '75px',
                        'display': 'flex',
                        'alignItems': 'center',
                          'justifyContent': 'center'
                    },
                    'cellClass': 'text-center unit-cell box-sizing-border-box'  # 添加unit-cell类
                },
                {
                    'headerName': "🥇",
                    'headerClass': 'text-center custom-header-border',
                    'field': "gold",
                    'flex': 15,
                    'cellStyle': {
                        'fontSize': '30px',
                        'textAlign': 'center',
                        'height': '75px',
                        'display': 'flex',
                        'alignItems': 'center',
                          'justifyContent': 'center'
                    },
                    'cellClass': 'text-center box-sizing-border-box'
                },
                {
                    'headerName': "🥈",
                    'headerClass': 'text-center custom-header-border',
                    'field': "silver",
                    'flex': 15,
                    'cellStyle': {
                        'fontSize': '30px',
                        'textAlign': 'center',
                        'height': '75px',
                        'display': 'flex',
                        'alignItems': 'center',
                          'justifyContent': 'center'
                    },
                    'cellClass': 'text-center box-sizing-border-box'
                },
                {
                    'headerName': "🥉",
                    'headerClass': 'text-center custom-header-border',
                    'field': "bronze",
                    'flex': 15,
                    'cellStyle': {
                        'fontSize': '30px',
                        'textAlign': 'center',
                        'height': '75px',
                        'display': 'flex',
                        'alignItems': 'center',
                          'justifyContent': 'center'
                    },
                    'cellClass': 'text-center box-sizing-border-box'
                },
                {
                    'headerName': "总数",
                    'field': "total",
                    'flex': 15,
                    'cellStyle': {
                          'fontSize': '30px',
                          'textAlign': 'center',
                          'height': '75px',
                          'display': 'flex',
                          'alignItems': 'center',
                          'justifyContent': 'center'
                    },
                    'cellClass': 'text-center box-sizing-border-box'
                },
            ]

            table = ui.aggrid({
                'columnDefs': columns,
                'rowData': [],
                'rowHeight': 75,
                'headerHeight': 75,  # 恢复表头高度
                # 'suppressHorizontalScroll': True,
                'height': '100%',
                'domLayout': 'normal',
                'rowClassRules': {
                    # 前三名高亮显示
                    'highlight-row': 'data.rank <= 3'
                },
                'defaultColDef': {
                    'sortable': False,
                    'filter': False,
                    'resizable': False,
                }
            }).classes('w-full h-full p-0')

        # 底部信息
        # ui.label('实时更新 | 数据权威发布').classes('absolute bottom-8 text-2xl font-bold opacity-90')

    # 更新时间显示
    def update_time():
        while True:
            time_label.text = time.strftime('%Y年%m月%d日 %H:%M:%S')
            time.sleep(1)

    # 更新标题
    def update_title(new_title):
        title_label.text = new_title

    # 注册数据更新回调
    comp_state.register_callback(update_display)
    comp_state.register_title_callback(update_title)

    # 启动自动刷新线程
    comp_state.start_auto_refresh()

    # 初始更新
    update_display()

    # 启动时间更新线程
    threading.Thread(target=update_time, daemon=True).start()


# 数据维护界面 - 使用表格布局显示单位、金银铜牌图标
def create_edit_screen():
    with ui.column().classes('p-8 w-full max-w-6xl mx-auto'):
        ui.label('比武竞赛数据维护系统').classes('text-3xl font-bold mb-8 text-center text-red-800')

        # 添加标题编辑区域
        with ui.card().classes('w-full p-4 mb-6 bg-yellow-50 border border-yellow-200'):
            with ui.row().classes('items-center w-full'):
                ui.label('大屏标题:').classes('text-lg font-bold text-gray-700')
                title_input = ui.input(
                    value=comp_state.title,
                    on_change=lambda e: comp_state.update_title(e.value)
                ).classes('flex-grow text-xl')
                ui.button('保存标题', on_click=lambda: comp_state.update_title(title_input.value),
                          color='primary').classes('px-4 py-2 bg-green-600 text-white')

        # 创建表格布局
        with ui.grid(columns=7).classes('w-full gap-4 bg-gray-100 p-4 rounded-lg shadow-md'):
            # 表头
            ui.label('序号').classes('font-bold text-lg text-center bg-yellow-200 py-2 rounded')
            ui.label('单位').classes('font-bold text-lg text-center bg-yellow-200 py-2 rounded')
            ui.html('<div class="font-bold text-center text-lg bg-yellow-200 py-2 rounded">🥇</div>')
            ui.html('<div class="font-bold text-center text-lg bg-yellow-200 py-2 rounded">🥈</div>')
            ui.html('<div class="font-bold text-center text-lg bg-yellow-200 py-2 rounded">🥉</div>')
            ui.label('总数').classes('font-bold text-lg text-center bg-yellow-200 py-2 rounded')
            ui.label('操作').classes('font-bold text-lg text-center bg-yellow-200 py-2 rounded')

            # 根据当前数据排序
            df = pd.DataFrame(comp_state.data)
            df = df.sort_values(
                by=['total', 'gold', 'silver', 'bronze'],
                ascending=[False, False, False, False]
            ).reset_index(drop=True)

            # 计算排名（考虑并列情况）
            display_data = []
            prev_total = None
            prev_rank = 0
            skip_count = 0

            for i, row in df.iterrows():
                current_total = (row['total'], row['gold'], row['silver'], row['bronze'])

                if current_total == prev_total:
                    # 并列情况
                    rank = prev_rank
                    skip_count += 1
                else:
                    # 新排名
                    rank = i + 1 - skip_count
                    prev_rank = rank
                    prev_total = current_total

                display_data.append({
                    'rank': rank,
                    'unit': row['unit'],
                    'gold': row['gold'],
                    'silver': row['silver'],
                    'bronze': row['bronze'],
                    'total': row['total']
                })

            # 数据行
            for idx, item in enumerate(display_data):
                unit = item['unit']

                # 排名 - 使用深红色圆形背景
                ui.label(str(item['rank'])).classes(
                    'text-center text-lg font-bold py-3 flex items-center justify-center '
                    'bg-red-800 text-yellow-400 rounded-full w-12 h-12 mx-auto'
                )

                # 单位名称 - 使用华文行楷字体
                ui.label(unit).classes(
                    'text-center text-lg font-bold py-3 flex items-center justify-center font-[华文行楷]')

                # 金牌输入
                gold_input = ui.number(
                    value=item['gold'],
                    min=0,
                    format='%.0f',
                    on_change=lambda e, u=unit: comp_state.update_score(u, 'gold', e.value)
                ).classes('w-full text-center text-lg py-2 flex items-center justify-center')

                # 银牌输入
                silver_input = ui.number(
                    value=item['silver'],
                    min=0,
                    format='%.0f',
                    on_change=lambda e, u=unit: comp_state.update_score(u, 'silver', e.value)
                ).classes('w-full text-center text-lg py-2 flex items-center justify-center')

                # 铜牌输入
                bronze_input = ui.number(
                    value=item['bronze'],
                    min=0,
                    format='%.0f',
                    on_change=lambda e, u=unit: comp_state.update_score(u, 'bronze', e.value)
                ).classes('w-full text-center text-lg py-2 flex items-center justify-center')

                # 总数显示 - 使用禁用的输入框
                total_input = ui.input(value=str(item['total'])).classes(
                    'w-full text-center text-lg py-2 bg-gray-200 font-bold flex items-center justify-center'
                ).props('disable')

                # 重置按钮
                ui.button('重置', on_click=lambda u=unit, g=gold_input, s=silver_input, b=bronze_input: [
                    g.set_value(0),
                    s.set_value(0),
                    b.set_value(0),
                    comp_state.update_score(u, 'gold', 0),
                    comp_state.update_score(u, 'silver', 0),
                    comp_state.update_score(u, 'bronze', 0)
                ]).classes(
                    'w-full py-2 bg-red-700 text-white hover:bg-red-800 text-lg flex items-center justify-center')

                # 实时更新总数
                def update_total(u=unit, t=total_input):
                    for data_item in comp_state.data:
                        if data_item['unit'] == u:
                            t.set_value(str(data_item['total']))

                comp_state.register_callback(lambda u=unit, t=total_input: update_total(u, t))

        # 添加操作按钮行
        with ui.row().classes('w-full justify-center mt-6 gap-4'):
            # 重置所有按钮
            ui.button('重置所有数据', on_click=lambda: reset_all_data(), color='red').classes(
                'py-3 px-8 text-lg bg-red-700 text-white hover:bg-red-800')

            # 导出Excel按钮
            ui.button('导出Excel', on_click=lambda: export_to_excel(), color='green').classes(
                'py-3 px-8 text-lg bg-green-600 text-white hover:bg-green-700')


# 导出Excel函数
def export_to_excel():
    """将当前数据导出为Excel文件"""
    try:
        # 创建DataFrame
        df = pd.DataFrame(comp_state.data)

        # 添加排名列
        df = df.sort_values(
            by=['total', 'gold', 'silver', 'bronze'],
            ascending=[False, False, False, False]
        ).reset_index(drop=True)

        # 计算排名（考虑并列情况）
        df['排名'] = 0
        prev_total = None
        prev_rank = 0
        skip_count = 0

        for i in range(len(df)):
            current_total = (df.at[i, 'total'], df.at[i, 'gold'], df.at[i, 'silver'], df.at[i, 'bronze'])

            if current_total == prev_total:
                df.at[i, '排名'] = prev_rank
                skip_count += 1
            else:
                rank = i + 1 - skip_count
                df.at[i, '排名'] = rank
                prev_rank = rank
                prev_total = current_total

        # 重新排序列
        df = df[['排名', 'unit', 'gold', 'silver', 'bronze', 'total']]
        df.columns = ['排名', '单位', '金牌', '银牌', '铜牌', '总分']

        # 导出为Excel
        timestamp = time.strftime("%Y%m%d_%H%M%S")
        filename = f"比武竞赛数据_{timestamp}.xlsx"
        df.to_excel(filename, index=False)

        # 显示成功通知
        ui.notify(f"数据已成功导出为: {filename}", type='positive')
        return True
    except Exception as e:
        ui.notify(f"导出失败: {str(e)}", type='negative')
        return False


# 重置所有数据函数
def reset_all_data():
    for item in comp_state.data:
        item['gold'] = 0
        item['silver'] = 0
        item['bronze'] = 0
        item['total'] = 0

    # 保存重置后的数据
    comp_state.save_state()
    comp_state.notify_update()
    ui.notify("所有数据已重置", type='info')


# 主控制界面
@ui.page('/')
def main_control():
    with ui.column().classes('h-screen w-full items-center justify-center gap-8 bg-gray-100'):
        ui.label('比武竞赛双屏控制系统').classes('text-4xl font-bold text-red-800')

        with ui.row().classes('gap-8'):
            with ui.card().classes(
                    'w-72 h-72 items-center justify-center gap-6 shadow-xl bg-red-50 border-2 border-red-700'):
                ui.icon('tv', size='xl', color='red').classes('text-4xl')
                ui.label('大屏展示').classes('text-2xl font-bold text-red-800')
                ui.button('打开展示屏', on_click=lambda: ui.navigate.to('/display')).classes(
                    'text-xl px-8 py-3 bg-red-700 text-white hover:bg-red-800')

            with ui.card().classes(
                    'w-72 h-72 items-center justify-center gap-6 shadow-xl bg-yellow-50 border-2 border-yellow-600'):
                ui.icon('edit', size='xl', color='amber').classes('text-4xl')
                ui.label('数据维护').classes('text-2xl font-bold text-amber-800')
                ui.button('打开维护屏', on_click=lambda: ui.navigate.to('/edit')).classes(
                    'text-xl px-8 py-3 bg-amber-600 text-white hover:bg-amber-700')

        ui.label('使用说明：在两台设备上分别打开展示屏和维护屏').classes('text-xl text-gray-700')
        ui.label('维护屏修改数据后，展示屏会自动实时更新').classes('text-xl text-gray-700')


# 创建页面
@ui.page('/display')
def display_page():
    if check_license():
        ui.notify(message='软件已过试用期，请购买正版软件.',close_button=True,type='negative',position='center')
        return
    create_display_screen()


@ui.page('/edit')
def edit_page():
    if check_license():
        ui.notify(message='软件已过试用期，请购买正版软件.',close_button=True,type='negative',position='center')
        return
    create_edit_screen();


if __name__ in {"__main__", "__mp_main__"}:
    logging.basicConfig(
        level=logging.INFO,
        format="%(levelname)s: %(message)s",
        stream=sys.stderr  # 确保使用 stderr
    )

    # 禁用 Uvicorn 的日志干扰
    logging.getLogger("uvicorn").handlers.clear()
    logging.getLogger("uvicorn").propagate = True  # 继承根日志配置
    ROOT = Path(__file__).parent
    app.add_static_files("/images", "images")
    # 添加关闭时的清理操作
    app.on_shutdown(comp_state.stop_auto_refresh)
    # 启动应用
    ui.run(
        title='比武竞赛系统',
        port=8080,
        dark=False,
        favicon='🏆',
        binding_refresh_interval=0.1,
        reload=False,
        log_config=None
    )